﻿using HalconDotNet;
using MachineVision.Core.Extensions;
using MachineVision.Core.TemplateMatch.Shared;
using Prism.Mvvm;

namespace MachineVision.Core.TemplateMatch.LocalDeformable
{
    public class LocalDeformableService : BindableBase, ITemplateMatchService
    {
        public LocalDeformableService()
        {
            Roi = new ROIParameter();
            Info = new()
            {
                Name = "find_local_deformable_model",
                Description =
                    "FindLocalDeformableModel — Find the best matches of a local deformable model in an image.",
                Parameters = new List<MethodParameter>()
                {
                    new MethodParameter()
                    {
                        Name = "Image",
                        Description = "Input image in which the model should be found."
                    },
                    new MethodParameter()
                    {
                        Name = "imageRectified",
                        Description = "Rectified image of the found model."
                    },
                    new MethodParameter()
                    {
                        Name = "vectorField",
                        Description = "Vector field of the rectification transformation."
                    },
                    new MethodParameter()
                    {
                        Name = "deformedContours",
                        Description = "Contours of the found instances of the model."
                    },
                    new MethodParameter()
                    {
                        Name = "modelID",
                        Description = "Handle of the model."
                    },
                    new MethodParameter()
                    {
                        Name = "angleStart",
                        Description = "Smallest rotation of the model."
                    },
                    new MethodParameter()
                    {
                        Name = "angleExtent",
                        Description = "Extent of the rotation angles."
                    },
                    new MethodParameter()
                    {
                        Name = "scaleRMin",
                        Description = "Minimum scale of the model in row direction."
                    },
                    new MethodParameter()
                    {
                        Name = "scaleRMax",
                        Description = "Maximum scale of the model in row direction."
                    },
                    new MethodParameter()
                    {
                        Name = "scaleCMin",
                        Description = "Minimum scale of the model in column direction."
                    },
                    new MethodParameter()
                    {
                        Name = "scaleCMax",
                        Description = "Maximum scale of the model in column direction."
                    },
                    new MethodParameter()
                    {
                        Name = "minScore",
                        Description = "Minimum score of the instances of the model to be found."
                    },
                    new MethodParameter()
                    {
                        Name = "numMatches",
                        Description =
                            "Number of instances of the model to be found (or 0 for all matches)."
                    },
                    new MethodParameter()
                    {
                        Name = "maxOverlap",
                        Description = "Maximum overlap of the instances of the model to be found."
                    },
                    new MethodParameter()
                    {
                        Name = "numLevels",
                        Description = "Number of pyramid levels used in the matching."
                    },
                    new MethodParameter()
                    {
                        Name = "greediness",
                        Description =
                            "“Greediness” of the search heuristic (0: safe but slow; 1: fast but matches may be missed)."
                    },
                    new MethodParameter()
                    {
                        Name = "resultType",
                        Description = "Switch for requested iconic result."
                    },
                    new MethodParameter()
                    {
                        Name = "genParamName",
                        Description = "The general parameter names."
                    },
                    new MethodParameter()
                    {
                        Name = "genParamValue",
                        Description = "Values of the general parameters."
                    },
                    new MethodParameter()
                    {
                        Name = "score",
                        Description = "Scores of the found instances of the model."
                    },
                    new MethodParameter()
                    {
                        Name = "row",
                        Description = "Row coordinates of the found instances of the model."
                    },
                    new MethodParameter()
                    {
                        Name = "column",
                        Description = "Column coordinates of the found instances of the model."
                    }
                },
                Preducessors = new List<string>()
                {
                    "CreateLocalDeformableModel",
                    "CreateLocalDeformableModelXld",
                    "ReadDeformableModel"
                }
            };
            TemplateParameter = new();
            RunParameter = new();
            Setting = new MatchResultSetting();
            MatchResult = new MatchResult();
        }

        public ROIParameter Roi { get; set; }
        public MethodInfo Info { get; set; }
        private LocalDeformableInputParameter templateParameter;

        /// <summary>
        /// 形状匹配模板参数
        /// </summary>
        public LocalDeformableInputParameter TemplateParameter
        {
            get { return templateParameter; }
            set
            {
                templateParameter = value;
                RaisePropertyChanged();
            }
        }
        private LocalDeformableRunParameter runParameter;
        private HTuple modelId;

        /// <summary>
        /// 形状匹配运行参数
        /// </summary>
        public LocalDeformableRunParameter RunParameter
        {
            get { return runParameter; }
            set
            {
                runParameter = value;
                RaisePropertyChanged();
            }
        }

        public async Task CreateTemplateAsync(HObject image, HObject hobject)
        {
            await Task.Run(() =>
            {
                var template = image.ReduceDomain(Roi).CropDomain();
                HOperatorSet.CreateLocalDeformableModel(
                    template.Rgb1ToGray(),
                    TemplateParameter.NumLevels,
                    TemplateParameter.AngleStart,
                    TemplateParameter.AngleExtent,
                    TemplateParameter.AngleStep,
                    TemplateParameter.ScaleRMin,
                    //TemplateParameter.ScaleRMax,
                    new HTuple(),
                    TemplateParameter.ScaleRStep,
                    TemplateParameter.ScaleCMin,
                    TemplateParameter.ScaleCMax,
                    TemplateParameter.ScaleCStep,
                    TemplateParameter.Optimization,
                    TemplateParameter.Metric,
                    TemplateParameter.Contrast,
                    TemplateParameter.MinContrast,
                    new HTuple(),
                    new HTuple(),
                    out modelId
                );
            });
        }

        public double GetRunTimeSpan(Action action)
        {
            return default;
        }

        private MatchResult matchResult;

        public MatchResult MatchResult
        {
            get { return matchResult; }
            set
            {
                matchResult = value;
                RaisePropertyChanged();
            }
        }

        private MatchResultSetting setting;

        public MatchResultSetting Setting
        {
            get { return setting; }
            set
            {
                setting = value;
                RaisePropertyChanged();
            }
        }

        private HWindow window;

        public HWindow Window
        {
            get { return window; }
            set
            {
                window = value;
                RaisePropertyChanged();
            }
        }

        public void Run(HObject image)
        {
            HTuple hv_Score = null;
            HTuple hv_Row = null;
            HTuple hv_Column = null;
            var timespan = SetTimerHelper.SetTimer(() =>
            {
                HOperatorSet.FindLocalDeformableModel(
                    image,
                    out RunParameter.ImageRectified,
                    out RunParameter.VectorField,
                    out RunParameter.DeformedContours,
                    modelId,
                    RunParameter.AngleStart,
                    RunParameter.AngleExtent,
                    RunParameter.ScaleRMin,
                    RunParameter.ScaleRMax,
                    RunParameter.ScaleCMin,
                    RunParameter.ScaleCMax,
                    RunParameter.MinScore,
                    RunParameter.NumMatches,
                    RunParameter.MaxOverlap,
                    RunParameter.NumLevels,
                    RunParameter.Greediness,
                    ((new HTuple("image_rectified")).TupleConcat("vector_field")).TupleConcat(
                        "deformed_contours"
                    ),
                    new HTuple(),
                    new HTuple(),
                    out hv_Score,
                    out hv_Row,
                    out hv_Column
                );
            });
            MatchResult.Results.Clear();
            for (int i = 0; i < hv_Score.Length; i++)
            {
                var row1 = Math.Round(hv_Row.DArr[i], 3);
                var col1 = Math.Round(hv_Column.DArr[i], 3);
                var score1 = Math.Round(hv_Score.DArr[i], 3);
                MatchResult.Results.Add(
                    new TemplateMatchResult()
                    {
                        Index = i + 1,
                        Row = row1,
                        Column = col1,
                        Score = score1,
                    }
                );
                if (Setting.IsShowCenter)
                    HOperatorSet.DispCross(Window, row1, col1, 20, score1);
                if (Setting.IsShowMatchRange)
                {
                    HOperatorSet.GetDeformableModelContours(out HObject contours, modelId, 1);
                    Window.DispObj(contours);
                }
                if (Setting.IsShowDisplayText)
                {
                    Window.SetString(
                        $"{row1} : {col1} : {score1}",
                        "image",
                        row1,
                        col1,
                        "black",
                        "true"
                    );
                }
            }
            MatchResult.TimeSpan = timespan;
            MatchResult.Message =
                $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}：匹配耗时:{timespan}ms,"
                + $"{(MatchResult.Results.Count > 0 ? $"匹配个数:{MatchResult.Results.Count}" : "未匹配相关数据")}";

            //return matchResult;
        }
    }
}
